package com.ruoyi.order.service;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信支付服务
 * 
 * @author ruoyi
 * @date 2025-01-27
 */
@Service
public class WechatPayService implements PayService {
    private Signer signer;

    private static final Logger log = LoggerFactory.getLogger(WechatPayService.class);
    /** appid */
    @Value("${wx.minApp.appId}")
    private String appId;
    /** 商户号 */
    @Value("${wx.pay.mchId}")
    private String merchantId;
    /** 商户API私钥路径 */
    @Value("${wx.pay.privateKeyPath}")
    private String privateKeyPath;
    /** 商户证书序列号 */
    @Value("${wx.pay.merchantSerialNumber}")
    private String merchantSerialNumber;
    /** 商户APIV3密钥 */
    @Value("${wx.pay.apiV3Key}")
    private String apiV3Key;

    @Value("${wx.pay.notifyUrl}")
    private String notifyUrl;

    private JsapiService jsapiService;
    @Value("${wx.pay.publicKeyId}")
    private String publicKeyId;
    @Value("${wx.pay.publickeyPath}")
    private String publickeyPath;

    @PostConstruct
    public void init() {
        try {
            log.info("开始初始化微信支付服务...");
            log.info("商户号: {}", merchantId);
            log.info("私钥路径: {}", privateKeyPath);
            log.info("证书序列号: {}", merchantSerialNumber);
            log.info("AppId: {}", appId);
            log.info("回调地址: {}", notifyUrl);

            // 检查配置参数
            if (merchantId == null || merchantId.isEmpty()) {
                throw new RuntimeException("商户号配置为空");
            }
            if (privateKeyPath == null || privateKeyPath.isEmpty()) {
                throw new RuntimeException("私钥路径配置为空");
            }
            if (merchantSerialNumber == null || merchantSerialNumber.isEmpty()) {
                throw new RuntimeException("证书序列号配置为空");
            }
            if (apiV3Key == null || apiV3Key.isEmpty()) {
                throw new RuntimeException("API V3密钥配置为空");
            }
            if (appId == null || appId.isEmpty()) {
                throw new RuntimeException("AppId配置为空");
            }

            // 检查私钥文件是否存在
            File privateKeyFile = new File(privateKeyPath);
            if (!privateKeyFile.exists()) {
                throw new RuntimeException("私钥文件不存在: " + privateKeyPath);
            }
            log.info("私钥文件存在: {}", privateKeyFile.getAbsolutePath());

            // 验证私钥文件格式
            // validatePrivateKeyFile(privateKeyPath);

            // 使用自动更新平台证书的RSA配置
            // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
            Config config = new RSAPublicKeyConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(privateKeyPath)
                    .publicKeyFromPath(publickeyPath)
                    .publicKeyId(publicKeyId)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
            signer = config.createSigner();

            jsapiService = new JsapiService.Builder().config(config).build();
            log.info("微信支付服务初始化成功");
        } catch (Exception e) {
            log.error("微信支付服务初始化失败", e);
            throw new RuntimeException("微信支付服务初始化失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证私钥文件格式
     */
    private void validatePrivateKeyFile(String filePath) throws IOException {
        try {
            String content = new String(Files.readAllBytes(Paths.get(filePath)));
            log.info("私钥文件内容前100字符: {}", content.substring(0, Math.min(100, content.length())));

            // 检查是否是PEM格式
            if (!content.contains("-----BEGIN PRIVATE KEY-----") &&
                    !content.contains("-----BEGIN RSA PRIVATE KEY-----")) {
                throw new RuntimeException("私钥文件格式不正确，应该是PEM格式");
            }

            // 检查文件大小
            File file = new File(filePath);
            long fileSize = file.length();
            log.info("私钥文件大小: {} bytes", fileSize);

            if (fileSize < 100) {
                throw new RuntimeException("私钥文件太小，可能不是有效的私钥文件");
            }

        } catch (IOException e) {
            throw new RuntimeException("读取私钥文件失败: " + e.getMessage(), e);
        }
    }

    /**
     * 创建支付订单（使用系统自动生成的订单号）
     * 
     * @param openid      用户openid
     * @param amount      金额（分）
     * @param description 商品描述
     * @param userId      用户ID
     * @return 支付参数
     */
    public Map<String, Object> createOrder(String openid, Integer amount, String description, Long userId) {
        String orderNo = generateOrderNo();
        return createOrderWithOutTradeNo(openid, amount, description, userId, orderNo);
    }

    /**
     * 创建支付订单（使用业务自定义订单号作为 out_trade_no）
     * 
     * @param openid      用户openid
     * @param amount      金额（分）
     * @param description 商品描述
     * @param userId      用户ID
     * @param outTradeNo  业务订单号
     * @return 支付参数
     */
    public Map<String, Object> createOrderWithOutTradeNo(String openid, Integer amount, String description, Long userId,
            String outTradeNo) {
        try {
            // 检查jsapiService是否已初始化
            if (jsapiService == null) {
                log.error("jsapiService未初始化，尝试重新初始化...");
                init();
                if (jsapiService == null) {
                    throw new RuntimeException("微信支付服务未正确初始化");
                }
            }

            // 创建支付请求
            PrepayRequest request = new PrepayRequest();
            Amount amountObj = new Amount();
            amountObj.setTotal(amount);
            request.setAmount(amountObj);
            request.setAppid(appId);
            request.setMchid(merchantId);
            request.setDescription(description);
            request.setNotifyUrl(notifyUrl);
            request.setOutTradeNo(outTradeNo);

            Payer payer = new Payer();
            payer.setOpenid(openid);
            request.setPayer(payer);

            // 调用微信支付API
            PrepayResponse response = jsapiService.prepay(request);

            // 返回支付参数
            Map<String, Object> result = new HashMap<>();
            result.put("orderNo", outTradeNo);
            result.put("prepayId", response.getPrepayId());
            result.put("package", "prepay_id=" + response.getPrepayId());
            result.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            result.put("nonceStr", UUID.randomUUID().toString().replace("-", ""));
            result.put("signType", "RSA");
            result.put("paySign", sigeWithRequestPayment(result));
            log.info("创建支付订单成功，业务订单号：{}，prepayId：{}", outTradeNo, response.getPrepayId());
            return result;

        } catch (Exception e) {
            log.error("创建支付订单失败", e);
            throw new RuntimeException("创建支付订单失败：" + e.getMessage());
        }
    }

    @Override
    public Map<String, Object> createWechatPayOrder(String openid, Integer amount, String description, Long userId,
            String outTradeNo) {
        return createOrderWithOutTradeNo(openid, amount, description, userId, outTradeNo);
    }

    public String sigeWithRequestPayment(Map<String, Object> result) {
        String prepayId = result.get("prepayId").toString();
        String timestamp = result.get("timeStamp").toString();
        String nonceStr = result.get("nonceStr").toString();
        String packageVal = "prepay_id=" + prepayId;
        String message = appId + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
        log.info("Message for RequestPayment signatures is[{}]", message);

        return signer.sign(message).getSign();
    }

    /**
     * 测试配置
     */
    public Map<String, Object> testConfig() {
        Map<String, Object> result = new HashMap<>();
        result.put("merchantId", merchantId);
        result.put("privateKeyPath", privateKeyPath);
        result.put("merchantSerialNumber", merchantSerialNumber);
        result.put("appId", appId);
        result.put("notifyUrl", notifyUrl);

        // 检查私钥文件
        File privateKeyFile = new File(privateKeyPath);
        result.put("privateKeyFileExists", privateKeyFile.exists());
        result.put("privateKeyFileAbsolutePath", privateKeyFile.getAbsolutePath());

        if (privateKeyFile.exists()) {
            result.put("privateKeyFileSize", privateKeyFile.length());
            try {
                String content = new String(Files.readAllBytes(Paths.get(privateKeyPath)));
                result.put("privateKeyFileContent", content.substring(0, Math.min(200, content.length())));
                result.put("isPemFormat", content.contains("-----BEGIN PRIVATE KEY-----") ||
                        content.contains("-----BEGIN RSA PRIVATE KEY-----"));
            } catch (IOException e) {
                result.put("readFileError", e.getMessage());
            }
        }

        // 检查jsapiService
        result.put("jsapiServiceInitialized", jsapiService != null);

        return result;
    }

    /**
     * 生成订单号
     * 
     * @return 订单号
     */
    private String generateOrderNo() {
        return "PAY" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8);
    }
}